#include "MysqlDao.h"
#include "ConfigManager.h"


MySqlPool::MySqlPool(const std::string& url, const std::string& user, const std::string& pass, const std::string& schema, int poolSize) 
	: m_url(url), m_user(user), m_passwd(pass), m_schema(schema), m_poolSize(poolSize), m_b_stop(false) {
	try {
		for (int i = 0; i < m_poolSize; ++i) {
			sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
			std::cout << "url = " << url << std::endl;
			auto* con = driver->connect(m_url, m_user, m_passwd);
			con->setSchema(m_schema);
			// 获取当前的连接的时间戳
			auto currentime = std::chrono::system_clock::now().time_since_epoch();
			// 将当前时间戳进行转换
			long long timestamp = std::chrono::duration_cast<std::chrono::seconds>(currentime).count();
			m_pool.emplace(std::make_unique<SqlConnection>(con, timestamp));
		}

		// 创建连接检测线程
		m_check_thread = std::thread([this]() {
			while (!m_b_stop) {
				checkConnection();
				std::this_thread::sleep_for(std::chrono::seconds(60)); // 每隔60s检测一次连接是否存活
			}
		});
		m_check_thread.detach();

	}
	catch (sql::SQLException& e) {
		std::cout << "mysql pool init failed, error is " << e.what() << std::endl;
	}
}

MySqlPool::~MySqlPool()
{
	std::lock_guard<std::mutex> guard(m_mutex);
	while (!m_pool.empty()) {
		m_pool.pop();
	}
}

// 检测存活连接
void MySqlPool::checkConnection()
{
	std::lock_guard<std::mutex> guard(m_mutex);
	int pool_size = m_pool.size();
	// 获取当前的连接的时间戳
	auto currentime = std::chrono::system_clock::now().time_since_epoch();
	// 将当前时间戳进行转换为
	long long timestamp = std::chrono::duration_cast<std::chrono::seconds>(currentime).count();
	for (int i = 0; i < pool_size; ++i) {
		auto con = std::move(m_pool.front());
		m_pool.pop();
		Defer defer([this, &con]() {
			// 在出作用域时自动归还到队列, 将其放置在连接队列的尾部
			m_pool.push(std::move(con));
		});

		if (timestamp - con->m_last_operator_time < 5) {
			continue;
		}

		try {
			std::unique_ptr<sql::Statement> statement(con->m_con->createStatement());
			statement->executeQuery("SELECT 1");
			con->m_last_operator_time = timestamp; // 改变当前连接最后一次操作的时间
			// std::cout << "execute timer alive query, currentime is " << timestamp << std::endl;
		}
		catch (sql::SQLException& e) {
			std::cout << "Error keeping alive query, currentime is " << timestamp << std::endl;
			// 重新创建新的连接并替换掉旧连接
			sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
			auto* newcon = driver->connect(m_url, m_user, m_passwd);
			newcon->setSchema(m_schema);
			con->m_con.reset(newcon);
			con->m_last_operator_time = timestamp;
		}
	}

}

std::unique_ptr<SqlConnection> MySqlPool::getConnection()
{
	std::unique_lock<std::mutex> lock(m_mutex);
	m_cond.wait(lock, [this] {
		if (m_b_stop) {
			return true;
		}

		return !m_pool.empty();
	});

	if (m_b_stop) {
		return nullptr;
	}

	std::unique_ptr<SqlConnection> con( std::move(m_pool.front()) );
	m_pool.pop();

	return con;
}

void MySqlPool::returnConnection(std::unique_ptr<SqlConnection> con)
{
	std::unique_lock<std::mutex> lock(m_mutex);
	if (m_b_stop) {
		return;
	}
	m_pool.push(std::move(con));
	m_cond.notify_one();
}

void MySqlPool::Close()
{
	m_b_stop = true;
	m_cond.notify_all();
}

MysqlDao::MysqlDao()
{
	auto& cfg = ConfigManager::getInstance();
	const auto& host = cfg["Mysql"]["Host"];
	const auto& port = cfg["Mysql"]["Port"];
	const auto& pwd = cfg["Mysql"]["Passwd"];
	const auto& schema = cfg["Mysql"]["Schema"];
	const auto& user = cfg["Mysql"]["User"];
	std::cout << "host = " << host << std::endl;
	std::cout << "port = " << port << std::endl;
	std::cout << "pwd = " << pwd << std::endl;
	std::cout << "schema = " << schema << std::endl;
	std::cout << "user = " << user << std::endl;

	m_pool.reset(new MySqlPool(host + ":" + port, user, pwd, schema, 5));
}

MysqlDao::~MysqlDao()
{
	m_pool->Close();
}

int MysqlDao::registerUser(const std::string& name, const std::string& email, const std::string& pwd, const std::string& icon)
{
	auto con = m_pool->getConnection();
	if (con == nullptr) {
		return false;
	}

	Defer defer([this, &con] {
		m_pool->returnConnection(std::move(con));
	});

	try {
		// 开始事务
		con->m_con->setAutoCommit(false);

		// 检查用户名是否已存在
		std::unique_ptr<sql::PreparedStatement> pstmt_email(con->m_con->prepareStatement("SELECT 1 FROM user WHERE email = ?"));
		pstmt_email->setString(1, name);
		// 执行查询
		std::unique_ptr<sql::ResultSet> res_email(pstmt_email->executeQuery());
		auto email_exist = res_email->next();
		if (email_exist) {
			con->m_con->rollback();
			con->m_con->setAutoCommit(true);
			std::cout << "email " << email << " exist";
			return 0;
		}

		// 准备查询用户名是否重复
		std::unique_ptr<sql::PreparedStatement> pstmt_name(con->m_con->prepareStatement("SELECT 1 FROM user WHERE name = ?"));
		// 绑定参数
		pstmt_name->setString(1, name);

		// 执行查询
		std::unique_ptr<sql::ResultSet> res_name(pstmt_name->executeQuery());
		auto name_exist = res_name->next();
		if (name_exist) {
			con->m_con->rollback();
			con->m_con->setAutoCommit(true);
			std::cout << "name " << name << " exist";
			return 0;
		}

		// 准备更新用户id
		std::unique_ptr<sql::PreparedStatement> pstmt_upid(con->m_con->prepareStatement("UPDATE user_id SET id = id + 1"));

		// 执行更新
		pstmt_upid->executeUpdate();

		// 获取更新后的 id 值
		std::unique_ptr<sql::PreparedStatement> pstmt_uid(con->m_con->prepareStatement("SELECT id FROM user_id"));
		std::unique_ptr<sql::ResultSet> res_uid(pstmt_uid->executeQuery());
		int newId = 0;
		// 处理结果集
		if (res_uid->next()) {
			newId = res_uid->getInt("id");
		}
		else {
			std::cout << "select id from user_id failed" << std::endl;
			con->m_con->rollback();
			return -1;
		}

		// 插入user信息
		std::unique_ptr<sql::PreparedStatement> pstmt_insert(con->m_con->prepareStatement("INSERT INTO user (uid, name, email, pwd, nick, icon) "
			"VALUES (?, ?, ?, ?,?,?)"));
		pstmt_insert->setInt(1, newId);
		pstmt_insert->setString(2, name);
		pstmt_insert->setString(3, email);
		pstmt_insert->setString(4, pwd);
		pstmt_insert->setString(5, name);
		pstmt_insert->setString(6, icon);
		// 执行插入
		pstmt_insert->executeUpdate();
		
		// 提交事务
		con->m_con->commit();
		con->m_con->setAutoCommit(true);

		std::cout << "newuser insert into user success" << std::endl;
		return newId;
	}
	catch (sql::SQLException& e) {
		if (con->m_con != nullptr) {
			con->m_con->rollback();
			con->m_con->setAutoCommit(true);
		}
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return -1;
	}

	return 0;
}

bool MysqlDao::checkEmail(const std::string& name, const std::string& email)
{
	auto con = m_pool->getConnection();
	try {
		if (con == nullptr) {
			return false;
		}

		// 准备查询语句
		std::unique_ptr<sql::PreparedStatement> pstmt(con->m_con->prepareStatement("SELECT email FROM user WHERE name = ?"));

		// 绑定参数
		pstmt->setString(1, name);

		// 执行查询
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		// 遍历结果集
		while (res->next()) {
			std::cout << "Check Email: " << res->getString("email") << std::endl;
			if (email != res->getString("email")) {
				m_pool->returnConnection(std::move(con));
				return false;
			}
			m_pool->returnConnection(std::move(con));
			return true;
		}

		return true;
	}
	catch (sql::SQLException& e) {
		m_pool->returnConnection(std::move(con));
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return false;
	}
}

bool MysqlDao::updatePwd(const std::string& name, const std::string& newpwd)
{
	auto con = m_pool->getConnection();
	try {
		if (con == nullptr) {
			return false;
		}

		// 准备查询语句
		std::unique_ptr<sql::PreparedStatement> pstmt(con->m_con->prepareStatement("UPDATE user SET pwd = ? WHERE name = ?"));

		// 绑定参数
		pstmt->setString(2, name);
		pstmt->setString(1, newpwd);

		// 执行更新
		int updateCount = pstmt->executeUpdate();

		std::cout << "Updated rows: " << updateCount << std::endl;
		m_pool->returnConnection(std::move(con));
		return true;
	}
	catch (sql::SQLException& e) {
		m_pool->returnConnection(std::move(con));
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return false;
	}
}

bool MysqlDao::checkPwd(const std::string& email, const std::string& pwd, UserInfo& userInfo)
{
	auto con = m_pool->getConnection();
	if (con == nullptr) {
		return false;
	}

	Defer defer([this, &con]() {
		m_pool->returnConnection(std::move(con));
	});

	try {
		// 准备SQL语句
		std::unique_ptr<sql::PreparedStatement> pstmt(con->m_con->prepareStatement("SELECT * FROM user WHERE email = ?"));
		pstmt->setString(1, email); // 将username替换为你要查询的用户名

		// 执行查询
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
		std::string origin_pwd = "";
		// 遍历结果集
		while (res->next()) {
			origin_pwd = res->getString("pwd");
			// 输出查询到的密码
			std::cout << "Password: " << origin_pwd << std::endl;
			break;
		}

		if (pwd != origin_pwd) {
			return false;
		}

		userInfo.name = res->getString("name");;
		userInfo.email = res->getString("email");
		userInfo.uid = res->getInt("uid");
		userInfo.pwd = origin_pwd;
		return true;
	}
	catch (const sql::SQLException& e) {
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return false;
	}
}





